package cn.itcast.health.admin.logs;

import cn.itcast.health.commons.resources.LOGMessage;
import cn.itcast.health.interfaces.logservice.LogBusinessFace;
import cn.itcast.health.vo.LogBusinessVo;
import com.alibaba.fastjson.JSON;
import org.apache.dubbo.config.annotation.Reference;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

@Aspect
@Component
public class OperationLogAspect {

    @Reference
    private LogBusinessFace logBusinessFace;

    /**
     * @Description 发生调用异常时记录日志（时间问题，先放在业务日志，后期可放在系统日志）
     */
    @AfterThrowing(value ="execution(@OperationLog * *(..))", throwing = "e")
    public  Object doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        System.out.println("=======》》》》》进入操作日志");
        //创建保存的日志对象
        LogBusinessVo logBusiness = new LogBusinessVo();


        //获取对象
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

        //获取方法名
        Method method = methodSignature.getMethod();
        //插入方法名
        logBusiness.setOperationMethod(method.getName());


        //根据方法名 获取其头上注解
        OperationLog operationLog = method.getAnnotation(OperationLog.class);
        //插入数据
        logBusiness.setState(0);    //状态 0 是错误信息
        logBusiness.setModuleName(operationLog.moduleName().getValue());       //模块名称
        logBusiness.setOperationType(operationLog.operationType().getValue()); //操作类型
        logBusiness.setOperationContent(operationLog.operationContent());      //操作内容
        logBusiness.setCreateTime(new Date());//存入错误时间


        //获取请求对象
        HttpServletRequest request  = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        //获取请求路径
        String requestURI = request.getRequestURI();
        logBusiness.setRequestURI(requestURI);
        //获取请求过来的类型
        String requestType = request.getMethod();
        logBusiness.setRequestType(requestType);
        //获取请求过来的ip地址
        String ip = request.getRemoteAddr();
        logBusiness.setRequestIp(ip);


        //创建存放消息的对象
        LOGMessage logMessage = new LOGMessage();
        //创建String 类型的缓存对象 并存入 “请求参数”
        StringBuffer params = new StringBuffer();
        //获取请求的参数
        if (joinPoint.getArgs() !=  null && joinPoint.getArgs().length > 0) {
            for ( int i = 0; i < joinPoint.getArgs().length; i++) {
                params.append(String.valueOf(joinPoint.getArgs()[i]));
            }
        }
        //存放请求参数
        logMessage.setRequestParameters(params.toString());
        //存入异常代码片段
        logMessage.setErrorMessage(e.getClass().getName());



        //把存放详细的变成json
        String message = JSON.toJSONString(logMessage);
        //存放消息
        logBusiness.setMessage(message);

        //远程调用dubbo,可以思考一下其他方案，比如消费队列
        logBusinessFace.SaveLogBusiness(logBusiness);
        return e;
    }

    /**
     * @Description 环绕日志
     */
    @Around(value ="execution(@OperationLog * *(..))")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("=======》》》》》进入操作日志");
        //执行切面方法
        Object result = joinPoint.proceed();
        initLog(joinPoint,result);
        return result;
    }

    /**
     * @Description  构建日志
     */
    private void initLog(JoinPoint joinPoint,Object result){
        //创建保存的日志对象
        LogBusinessVo logBusiness = new LogBusinessVo();

        //记录注解日志内容
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        //获取方法名
        Method method = methodSignature.getMethod();
        //插入方法名
        logBusiness.setOperationMethod(method.getName());

        //根据方法名 获取其头上注解
        OperationLog operationLog = method.getAnnotation(OperationLog.class);
        //插入数据
        logBusiness.setState(1);   //方法正常执行完
        logBusiness.setModuleName(operationLog.moduleName().getValue());   //模块名称
        logBusiness.setOperationType(operationLog.operationType().getValue());  //操作类型
        logBusiness.setOperationContent(operationLog.operationContent());        //操作内容
        logBusiness.setCreateTime(new Date());//存入时间


        //获取请求对象
        HttpServletRequest request  = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        //获取请求路径
        String requestURI = request.getRequestURI();
        logBusiness.setRequestURI(requestURI);
        //获取请求过来的类型
        String requestType = request.getMethod();
        logBusiness.setRequestType(requestType);
        //获取请求过来的ip地址
        String ip = request.getRemoteAddr();
        logBusiness.setRequestIp(ip);


        //创建存放消息的对象
        LOGMessage logMessage = new LOGMessage();
        //创建String 类型的缓存对象 并存入 “请求参数”
        StringBuffer params = new StringBuffer();
        //获取请求的参数
        if (joinPoint.getArgs() !=  null && joinPoint.getArgs().length > 0) {
            for ( int i = 0; i < joinPoint.getArgs().length; i++) {
                params.append(String.valueOf(joinPoint.getArgs()[i]));
            }
        }
        //存放请求参数
        logMessage.setRequestParameters(params.toString());
        //存放返回参数
        logMessage.setReturnParameters(JSON.toJSON(result).toString());


        //把存放详细的变成json
        String message = JSON.toJSONString(logMessage);
        //存放消息
        logBusiness.setMessage(message);


        //远程调用dubbo,可以思考一下其他方案，比如消费队列
        logBusinessFace.SaveLogBusiness(logBusiness);
    }
}
